// 12.2.2 非类型参数
// 非类型参数（Non-type Template Parameters，简称NTTP）是C++模板系统中另一个重要的参数类别，它允许我们使用编译时常量值作为模板参数。以下是关于非类型参数的详细解释：

// 基本语法
// 非类型参数的声明需要指定具体的类型：
template <typename T, int Size>
class Array
{
    T elements[Size]; // 使用Size作为数组大小
};

// 使用示例
Array<double, 10> doubleArray; // 创建一个包含10个double的数组

// 允许的非类型参数类型
// C++标准规定了可以用作非类型参数的类型：
// 1.整型和枚举类型：
template <int N, char C, enum Color E>
class Example1 {};

// 2.指针类型：
template <int *P>
class Example2
{
};

// 3.引用类型：
template <int &R>
class Example3
{
};

// 4.成员指针类型：
template <int Class::*PMD>
class Example4
{
};

// 5.std::nullptr_t（C++11起）：
template <std::nullptr_t N>
class Example5
{
};

// 6.字面量类（C++20起）：
template <std::string_view Str> // C++20允许
class Example6
{
};

// 不允许的非类型参数类型
// 以下类型不能用作非类型参数（C++20之前）：
// 浮点类型（float, double）
// 类类型（class, struct）
// 字符串字面量
// 函数类型（但函数指针可以）

// 非类型参数的值限制
// 非类型参数的值必须是编译时常量表达式：
template <int N>
class ConstantExample
{
};

const int c = 42;
ConstantExample<c> obj1; // 正确：c是编译时常量

int v = 42;
// ConstantExample<v> obj2;  // 错误：v不是编译时常量

// 非类型参数的用途
// 非类型参数有多种常见用途：
// 1.固定大小的容器：
template <typename T, size_t N>
class FixedArray
{
    T data[N];
};

// 2.编译时计算：
template <int N>
struct Factorial
{
    static constexpr int value = N * Factorial<N - 1>::value;
};

template <>
struct Factorial<0>
{
    static constexpr int value = 1;
};

// 3.策略选择：
template <typename T, bool ThreadSafe>
class Container
{
    // 根据ThreadSafe选择不同的实现
};

// 4.编译时优化：
template <int UnrollCount>
void unrolledLoop() {
    // 编译时展开循环
};

// 默认非类型参数
// 非类型参数也可以有默认值：
template <typename T, int Size = 10>
class DefaultSizeArray
{
    T elements[Size];
};

DefaultSizeArray<int> array; // Size默认为10
